package com.odyssey.player;

import org.anddev.andengine.entity.Entity;
import org.anddev.andengine.entity.sprite.AnimatedSprite;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTile;
import org.anddev.andengine.entity.modifier.MoveXModifier;
import org.anddev.andengine.entity.modifier.MoveYModifier;

import java.util.Vector;

import com.odyssey.common.Direction;

import com.odyssey.common.Circle;
import com.odyssey.common.Coordinate;
import com.odyssey.common.Definitions;
import com.odyssey.enemies.Enemy;
import android.util.Log;


public class Player extends Entity
{
  final Direction left = Direction.LEFT;
  final Direction right = Direction.RIGHT;
  final Direction forward = Direction.FORWARD;

  TiledTextureRegion pTexture;
  Coordinate pLoc;
  private Circle pCol;

  private AnimatedSprite pSprite;
  private float pTime;
  private Direction facing;
  Direction oldFacing;
  private boolean alive;
  private boolean jump;
  private boolean fall;
  public boolean jumpSoundFlag;
  private int jumpsLeft;

  //constructor ***********************************************************
  public Player(final int xi, final int yi, final int mapWidth, final int mapHeight, final TiledTextureRegion texture)
  {

    super(0,0); //init entity
    setJump(false);
    setFall(false);
    pLoc = new Coordinate(xi, yi);
    pTexture = texture;
    pSprite = new AnimatedSprite(pLoc.x, pLoc.y, pTexture);
    setpCol(new Circle(xi + (int)(pSprite.getWidth()/2),yi + (int) (pSprite.getHeight()/2),
    		pSprite.getWidth() > pSprite.getHeight() ? 
        (int) (pSprite.getWidth()/2) : (int) (pSprite.getHeight()/2)));    
    setFacing(Direction.FORWARD);
    oldFacing = Direction.FORWARD;
    setAlive(true);

  }

  //player commands**************************************************

  private void movePlayer (int newX, final AnimatedSprite playerSprite) 
  {   
    MoveXModifier moveX= new MoveXModifier(this.pTime, this.pLoc.x, newX);
    playerSprite.registerEntityModifier(moveX);   
  }

  private void playerVertMove (int yAmt, final AnimatedSprite playerSprite) 
  {
    MoveYModifier moveY = new MoveYModifier(this.pTime, this.pLoc.y, yAmt);
    playerSprite.registerEntityModifier(moveY);
  }

  public void jump() 
  {
    this.setJump(true);
    this.jumpsLeft = 75;
    this.jumpSoundFlag = true;
  }



  //miscellaneous****************************************************


  //getters & setters************************************************


  public boolean isAlive()
  {
    return alive;
  }

  public void setAlive(boolean alive)
  {
    this.alive = alive;
  }

  public Direction getFacing()
  {
    return facing;
  }

  public void setFacing(Direction facing)
  {
    this.facing = facing;
  }

  public boolean isJump()
  {
    return jump;
  }

  public void setJump(boolean jump)
  {
    this.jump = jump;
  }

  public boolean isFall()
  {
    return fall;
  }

  public void setFall(boolean fall)
  {
    this.fall = fall;
  }

  public Circle getpCol()
  {
    return pCol;
  }

  public void setpCol(Circle pCol)
  {
    this.pCol = pCol;
  }

  public void changeFacing (String dir) 
  {
    if (dir.equalsIgnoreCase("LEFT")) 
    {
      this.setFacing(Direction.LEFT);
    }
    else if (dir.equalsIgnoreCase("RIGHT"))
    {
      this.setFacing(Direction.RIGHT);
    }
    else 
    {
      this.setFacing(Direction.FORWARD);
    }
  }

  public void changeOldFacing (Direction dir) 
  {
    if (dir.equals(this.left)) 
    {
      this.oldFacing = Direction.LEFT;
    }
    else if (dir.equals(this.right))
    {
      this.oldFacing = Direction.RIGHT;
    }
    else 
    {
      this.oldFacing = Direction.FORWARD;
    }
  }

  public boolean changedDirection () 
  {
    if (this.getFacing().equals(this.left) && (this.oldFacing.equals(this.right) || (this.oldFacing.equals(this.forward)))) 
    {
      return true;
    }
    else if (this.getFacing().equals(this.right) && (this.oldFacing.equals(this.left) || (this.oldFacing.equals(this.forward)))) 
    {
      return true;
    }
    else if (this.getFacing().equals(this.forward) && ((this.oldFacing.equals(this.left)) || (this.oldFacing.equals(this.right)))) 
    {
      return true;
    }
    else 
    {
      return false;
    }
  }


  //collision & falling stuff****************************************

  private boolean falling (Coordinate pLoc, TMXTile below) 
  {
    if (this.getpCol().y + (pSprite.getHeight()/2) == Definitions.mapHeight) 
    {
      this.setFall(false);
      // insert DEATH!
      this.setAlive(false);
      return false;
    }
    else if (below.getGlobalTileID() == 124) 
    {
      this.setFall(false);
      return false;
    }
    else 
    {
      //Log.v("Odyssey", "belowTileId: " +below.getGlobalTileID());
      this.setFall(true);
      return true;
    }
  }

  private boolean collision (Coordinate pLoc, Circle pCol, TMXTile left, TMXTile right) 
  {
    //Implement collision detection
    if (this.getFacing().equals(this.left))
    {
      if (this.getpCol().x - (pSprite.getWidth()/2) == 0)
      {
        return true;
      }
      else if (left.getGlobalTileID() == 124)
      {
        return true;
      }
      else 
      {
        return false;
      }
    }
    else if (this.getFacing().equals(this.right))
    {
      if (this.getpCol().x + (pSprite.getWidth()/2) == Definitions.mapWidth)
      {
        return true;
      }
      else if (right.getGlobalTileID() == 124)
      {
        return true;
      }
      else 
      {
        return false;
      }
    }
    else 
    {
      Log.v("Odyssey", "Odd error!!");
      return false; //(somehow got here with forward)

    }
  }

  private boolean collideEnemy (Vector <Enemy> enList) 
  {

    int i;
    Circle enemyCir;
    Enemy enemy;
    int leftMinDist, rightMinDist, aboveMinDist, belowMinDist;
    int xDist, yDist;
    boolean returnStatus = false;

    final int numEnemies = enList.size();

    for( i = 0; i < numEnemies; i++) {
      enemy = enList.get(i);
      enemyCir = enemy.getCircle();

      leftMinDist = 5 - ((int)this.pSprite.getWidth() / 2) - (int)enemyCir.r;
      rightMinDist = -5 + ((int)this.pSprite.getWidth() / 2) + (int)enemyCir.r;
      aboveMinDist = 5 - ((int)this.pSprite.getHeight() / 2) - (int)enemyCir.r;
      belowMinDist = -5 + ((int)this.pSprite.getHeight() / 2) + (int)enemyCir.r;

      xDist = Math.abs(this.getpCol().x - enemyCir.x);
      yDist = Math.abs(this.getpCol().y - enemyCir.y);

      //Log.v("Odyssey", "Lmin: " +leftMinDist + ", Rmin: " +rightMinDist + ", Amin: " + aboveMinDist + ", Bmin: " +belowMinDist);
      //Log.v("Odyssey", "xPlayer: " +this.pCol.x + ", yPlayer: " +this.pCol.y);
      //Log.v("Odyssey", "xMob: " +enemyCir.x + ", yPlayer: " +enemyCir.y);
      //Log.v("Odyssey", "xDist: " +xDist + ", yDist: " +yDist);

      if((xDist < leftMinDist || xDist < rightMinDist) && (yDist < aboveMinDist || yDist < belowMinDist)) {
        if (returnStatus == false) {
          Log.v("Odyssey", "I hit a enemy!!!");
          returnStatus = true;
        }
      }
    }

    if (returnStatus == true) {
      return true;
    }
    else {
      return false;
    }
  }





  //update loop******************************************************
  public void updateTime (float elapseTime)
  {
    this.pTime = elapseTime;
  }

  public void updateAnimation(final AnimatedSprite playerSprite) 
  {
    if (this.getFacing().equals(this.left)) {
      playerSprite.animate(new long[]{200, 200, 200}, 9, 11, true);
      //Log.v("Odyssey", "Animating Left");
    }
    else if (this.getFacing().equals(this.right))
    {
      playerSprite.animate(new long[]{200, 200, 200}, 3, 5, true);
      //Log.v("Odyssey", "Animating Right");
    }
    else 
    {
      playerSprite.animate(new long[]{200, 200, 200}, 6, 8, true);
      //Log.v("Odyssey", "Animating Forward");
    }
  }


  public void update (AnimatedSprite playerSprite, TMXTile left, TMXTile right, TMXTile above, TMXTile below, Vector<Enemy> enList) 
  {
    //Log.v("Odyssey", "Updating");

    if(collideEnemy(enList)) 
    {
      this.setAlive(false);
      return;
    }

    if (falling(this.pLoc, below) && (this.isJump() == false)) 
    {
      //Log.v("Odyssey", "Ahh I'm Falling!!");
      playerVertMove(this.pLoc.y+1, playerSprite);
      this.pLoc.y ++;
      this.getpCol().y ++;
    }
    else if (this.isJump()) 
    {
      if(this.pLoc.y == 0) {
        Log.v("Odyssey", "top of map!!");
        this.setJump(false);
        this.jumpsLeft = 0;
      }
      else if(above.getGlobalTileID() == 124)
      {
        //Your hitting a platform above
        this.jumpsLeft = 0;
        this.setJump(false);
      }
      else 
      {
        //Log.v("Odyssey", "do jump!!");
        playerVertMove(this.pLoc.y-1, playerSprite);
        this.pLoc.y --;
        this.getpCol().y --;
        this.jumpsLeft --;
        if (this.jumpsLeft == 0) 
        {
          this.setJump(false);
        }
      }
    }

    if (this.getFacing().equals(Direction.FORWARD))
    {
      return;
    }     
    else if (this.getFacing().equals(Direction.RIGHT)) 
    {
      if (collision(this.pLoc, this.getpCol(), left, right)) 
      {
        //Log.v("Odyssey", "Player Collided!!");
        return;
      }
      else 
      {
        // Move right
        movePlayer(this.pLoc.x + 1, playerSprite);
        this.pLoc.x ++;
        this.getpCol().x ++;
      }
    }
    else 
    {
      if (collision(this.pLoc, this.getpCol(), left, right)) 
      {
        //Log.v("Odyssey", "Player Collided!!");
        return;
      }
      else 
      {
        // Move left
        movePlayer(this.pLoc.x - 1,  playerSprite);
        this.pLoc.x --; 
        this.getpCol().x --;
      }
    }
  }


}